A glowing rounded rectangle outline with a soft halo around it

Focus rings you can actually see

Jul 22, 2026 6 min

Every design system I have worked in eventually files the same ticket: the focus ring is too loud. It gets softened, then thinned, then given an opacity, and about a year later somebody discovers that you cannot tab through the checkout.

I understand the impulse. A default focus ring is genuinely ugly. It is also the only thing standing between a keyboard user and a page they cannot navigate, so the fix is to draw a better one, not a quieter one.

The ring is not decoration

A focus ring answers one question: where am I? It has to answer it from across the room, at a glance, on whatever background it happens to land on. That is a much harder job than a hover state, and we keep designing it as though it were an easier one.

Two properties do almost all the work.

  • Contrast against the element behind it, not against the page
  • Enough offset that the ring reads as a separate object rather than a border

Get those right and you can make the ring as tasteful as you like.

Use the outline, not the shadow

For years the trick was box-shadow, because outlines could not follow border radius. They can now, everywhere, and outlines have a property shadows do not: they are never clipped by overflow: hidden.

:where(a, button, input, select, [tabindex]):focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

That is the whole thing. Two lines, one token, and it inherits your brand colour for free.

Offset is the part people skip

An outline with no offset looks like a border that got thicker, which reads as a state change rather than a location. Two pixels of daylight between the element and the ring is the difference between this input changed and you are here.

On a dark control sitting on a dark surface you may need a second ring in the background colour underneath the first. It is worth the extra line.

focus-visible, not focus

The reason everyone wanted the ring gone in the first place was that it fired on mouse clicks. :focus-visible fixed that in 2022 and I still find :focus in new code most weeks.

If you take one thing from this: search your codebase for outline: none right now. Whatever you find, there is a good chance nothing replaced it.